-- 
-- Nuevo campo CodAmbEmp en valores para controlar la unicidad por empresa
-- Nuevo campo observaciones en empresas de uso libre pero que ayuda a determinar que empresas no son ficticias <GRUPO> 
-- (util en este asunto de los valores)  
--

ALTER TABLE VAL
	ADD COLUMN CodAmbEmp varchar;
	
COMMENT ON COLUMN public.val.CodAmbEmp
    IS 'Empresa donde el valor existe';
	
ALTER TABLE public.val
    ADD CONSTRAINT gestion_ai_ambempval FOREIGN KEY (codambemp)
    REFERENCES public.ambemp (cod) MATCH SIMPLE
    ON UPDATE CASCADE
    ON DELETE RESTRICT;

ALTER TABLE AMBEMP
   ADD COLUMN observaciones VARCHAR;
   
COMMENT ON COLUMN public.ambemp.observaciones
    IS 'Nuevo campo de uso libre en empresas';
    
-- Funcion de trigger de determinacion de la empresa del valor en Insert o Update de CTEM

CREATE OR REPLACE FUNCTION public.tg_ctem_ins_upd_valores()
    RETURNS trigger
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE NOT LEAKPROOF
AS $BODY$
DECLARE
	vIdPadCOMM 			pad.id%TYPE;
	vIdPadCTEM 			ctem.idpad%TYPE;
	vUltIdPadPOSTA 		pad.id%TYPE;
	vUltSignoCTEM		INTEGER;
	vCodAmbEmpValor 	val.codambemp%TYPE;
	vDeboCambiar boolean;
BEGIN
-- Cuando inserto un ctem y apunta a un valor (que recien lo guarde), guardo en val.idpadquelotiene el idpad que tiene ese valor, con el siguiente criterio:
-- Si el signo es de entrada, es el ctem.idpad, si es de salida sera el comm.idpad.
-- Ejemplos:
--      Un cheque recibido sera de entrada y tendra el idpad de la caja.
--      Un cheque entregado tendra el idpad del proveedor, que es el idpad del comm, SIEMPRE QUE NO SEA UN IDPAD DE FONDOS porque si no queda en poder de ese idpad.
--      En una transferencia de fondos, primero tendra erroneamente el idpad del comm y al toque le pondra el idpad del ctem porque la entrada se guarda despues que la salida.
--      Para los casos de un pago sin entidad (el comm.idpad es null), este campo quedara en null indicando que no se puede identificar el idpad que lo tiene.
-- Nota para el UPDATE: Se ejecuta tambien este trigger pero me aseguro que no exista otro ctem posterior apuntando a ese valor. Si existe no cambio nada porque sigue estando en el idpad del ultimo mov.
--                                        Uso OLD.idval y OLD.aaoid poque nunca debieran cambiar en un update del ctem. (ojala).
--                                        Uso la variable intermedia vDeboCambiar porque usando un solo if con and y or combinados, el motor 8.3 evaluaba toda la condicion, inclusive el 'exists' en un insert al dope. (Edu).
-- El unico caso por donde se puede escapar la tortuga para mantener idpadquelotiene actualizado es si se modificase el comm.idpad sin modificar la pata ctem y por lo tanto no pasa por este trigger.
vDeboCambiar = FALSE;
IF (NEW.IdVal IS NOT NULL) THEN
	IF (TG_OP = 'INSERT') THEN
		vDeboCambiar = TRUE;
	ELSE
		IF ( not exists (select * from ctem where ctem.idval = OLD.IdVal and ctem.aaoid > OLD.aaoid and ctem.idcomm <> OLD.idcomm) ) THEN
			vDeboCambiar = TRUE;
		END IF;
	END IF;
END IF;
IF (vDeboCambiar = FALSE) THEN
	RETURN NEW;
END IF;
-- Recupero en vIdPadCOMM el comm.idpad si es de una entidad que NO puede ser dueÃÂ±a de valores (padr.cp='E'). Caso contrario vIdPadCOMM = NULL.
-- Nota del 9 de Mayo del 2020 (Edu Cuarentena): Se volvio a agregar el AND padr.cp = 'E' porque sin eso hubo problemas en Santa Monica.
--      Se sacaba un cheque de la caja hacia el eter, pero como el comm.idpad era tambien el de la caja, siempre el cheque quedaba en esa caja.
--      En enero de este anio se habia sacado ese control porque Eligom tenia el rubro tarjetas como de fondos, cuando deberia ser de entidades.
--      No quedo clara esa situacion, posiblemente se deba modificar en Eligom el rubro tarjetas como de entidades...
SELECT comm.idpad INTO vIdPadCOMM
FROM comm
JOIN pad ON pad.id = comm.idpad
JOIN padr ON padr.tipopada = pad.tipopada AND padr.cod = pad.codpadr
WHERE comm.id = NEW.idcomm AND padr.cp = 'E';

-- Recupero en vIdPadCTEM el ultimo ctem.idpad que tiene este valor y en este comprobante.
-- El orden de recuperacion dara prioridad a las entradas y luego las salidas siempre que sea una entidad de fondos (que puede ser propietaria de valores).
-- Esto es asi porque no se puede controlar el orden de grabacion en Hibernate (Java).

SELECT ctem.idpad, ctem.signo INTO vIdPadCTEM, vUltSignoCTEM
FROM ctem 
	WHERE ctem.idcomm = NEW.idcomm AND ctem.idval = NEW.idval
	ORDER BY ctem.signo desc
LIMIT 1;

-- Si el ultimo signo del ctem para entidades que manejan valores fue una entrada, el valor lo tiene esa entidad, si no, se infiere que lo tendria la entidad del comprobante que no maneja valores.

IF (vUltSignoCTEM = 1) THEN
	vUltIdPadPOSTA = vIdPadCTEM;
ELSE
	vUltIdPadPOSTA = vIdPadCOMM;
END IF;
--
-- Cargo la empresa del valor si es posible deducirla a traves de su sucursal
-- Primero si el esquema de empresas-sucursales es compatible (no hay sucursales que pertenezcan a dos )
-- empresas sin ser estas <GRUPO> -- si no puedo determinar la empresa dejo la que había en el valor (coalesce)
--
	vCodAmbEmpValor := NULL;

	IF NOT EXISTS (SELECT count(codambemp) 
			  FROM ambempsuc
			  INNER JOIN ambemp ON ambemp.cod = ambempsuc.codambemp
			  WHERE position('<GRUPO>' in UPPER(coalesce(ambemp.observaciones,''))) = 0
			  GROUP BY codambsuc
			  HAVING COUNT(*) > 1) 
	THEN
	  vCodAmbEmpValor := (SELECT ambempsuc.codambemp 
		  		FROM ambempsuc
		  		INNER JOIN ambemp ON ambemp.cod = ambempsuc.codambemp
		  		WHERE position('<GRUPO>' in UPPER(coalesce(ambemp.observaciones,''))) = 0 AND
		  		ambempsuc.codambsuc = (SELECT COMM.CodAmbSuc FROM COMM WHERE NEW.IDCOMM = COMM.ID));
	END IF;

	UPDATE Val SET idpadquelotiene = vUltIdPadPOSTA, codambemp = coalesce(vCodAmbEmpValor, codambemp)
	   WHERE Id = NEW.IdVal and coalesce(idpadquelotiene, 0) <> coalesce(vUltIdPadPOSTA, 0);
	RETURN NEW;

-- ===================================================  QUERY PARA REGENERAR LOS IDPADQUELOTIENE  =========================================== --
-- === Para analizar IMPACTO del update se puede EJECUTAR lo encerrado entre 'Para ver diferencias..' y 'Fin de Para ver diferencias... ' (Edu cuarentena 2020).===== */

/*
UPDATE val SET idpadquelotiene = z.idpadquelotiene_posta
FROM 

(
-- Para ver diferencias
SELECT y.fechaemision, y.idval, y.tipovalt, y.nro, y.ultsigno, y.ultidpadcom, y.ultidpadmov, y.idpadquelotiene, y.ultidpadcom_posta, y.idpadquelotiene_posta
FROM
(
SELECT x.fechaemision, x.idval, x.tipovalt, x.nro, x.ultsigno, x.ultidpadcom, x.ultidpadmov, x.idpadquelotiene, x.ultidpadcom_posta, 
       case when x.ultsigno = 1 then x.ultidpadmov else x.ultidpadcom_posta end as idpadquelotiene_posta
FROM
(
SELECT val.fechaemision, val.id as idval, val.tipovalt, val.nro, v.ultsigno, v.ultidpadcom, v.ultidpadmov, val.idpadquelotiene, 
       case when padr.cp = 'E' then pad.id else null end as ultidpadcom_posta
FROM vval_p v
JOIN val on v.id = val.id
LEFT JOIN pad ON v.ultidpadcom = pad.id
LEFT JOIN padr ON pad.tipopada = padr.tipopada AND pad.codpadr = padr.cod
ORDER BY val.fechaemision
) x
ORDER BY x.fechaemision
) y
WHERE coalesce(y.idpadquelotiene,0) <> coalesce(y.idpadquelotiene_posta, 0)
ORDER BY y.fechaemision
-- Fin de Para ver diferencias...
) z

WHERE val.id = z.idval;
*/
-- ===================================================  FIN QUERY REGENERAR =========================================== --

END;
$BODY$;

ALTER FUNCTION public.tg_ctem_ins_upd_valores()
    OWNER TO abacouser;

--
-- Procedimiento que verifica la unicidad del valor (se llama desde gestion.exe)
--

DROP FUNCTION IF EXISTS public.verifica_unicidad_valor(character varying, character varying, character varying, integer, integer, numeric, character varying);

CREATE OR REPLACE FUNCTION public.verifica_unicidad_valor(
	ptipovalt character varying,
	pnro character varying,
	pcodvalbto character varying,
	pidpadorigen integer,
	pid integer,
	pimpomoneda numeric,
	pcodambsuc character varying)
    RETURNS boolean
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE 
AS $BODY$
DECLARE
	vIdVal   int4;
	vIdCtem  int4;
	vTipoCom ComM.TipoCom%TYPE;
	vLetra   ComM.Letra%TYPE;
	vPtoVta  Comm.NroPtoVta%TYPE;
	vNro     ComM.Nro%TYPE;
	vFecha   ComM.Fecha%TYPE;
	vTexto   varchar(4000);
	vVerificaUnicidad   valt.VerificaUnicidad%Type;
	vchequera           valt.chequera%Type;
	vImpoMoneda       	val.impomoneda%type;
	vMismoImpo  	boolean;
	vcheqxbanco 	int4;
	vCodAmbEmp      val.codambemp%TYPE;
BEGIN
select VerificaUnicidad,Chequera 
into vVerificaUnicidad, vChequera
from Valt where tipo=pTipoValt;

IF (vVerificaUnicidad = 'S') THEN
	vIdVal := NULL;
-- Verifica si existe el tipo de valor del valor ingresado controla unicidad.
-- Verifica la unicidad. La última parte de la condición es para que (NULL = NULL) de verdadero, que es el caso de IdPadOrigen y CodValBto.
    vCodAmbEmp := NULL;
 
	IF NOT EXISTS (SELECT count(ambempsuc.codambemp) 
		  FROM ambempsuc
		  INNER JOIN ambemp ON ambemp.cod = ambempsuc.codambemp
		  WHERE ambempsuc.codambsuc = pCodAmbSuc AND position('<GRUPO>' in UPPER(coalesce(ambemp.observaciones,''))) = 0
		  HAVING COUNT(*) > 1) 
	THEN
		vCodAmbEmp := (SELECT ambempsuc.codambemp 
		  				FROM ambempsuc
		  				INNER JOIN ambemp ON ambemp.cod = ambempsuc.codambemp
		  				WHERE ambempsuc.codambsuc = pCodAmbSuc AND position('<GRUPO>' in UPPER(coalesce(ambemp.observaciones,''))) = 0);
		  
	END IF;
    


	SELECT id, ImpoMoneda INTO vIdVal, vImpoMoneda
	FROM val
	WHERE ((pID IsNull) or (id <> pID)) and (TipoValt = pTipoValt) AND (Nro = pNro) 
	    AND ((codambemp is null) OR (coalesce(CodAmbEmp,'') = coalesce(VCodAmbEmp,''))) AND
		((Coalesce(CodValBto,'') = pCodValBto AND IdPadOrigen = pIdPadOrigen) OR
		(CodValBto IS NULL AND pCodValBto IS NULL AND IdPadOrigen IS NULL AND pIdPadOrigen IS NULL) OR
		(CodValBto IS NULL AND pCodValBto IS NULL AND IdPadOrigen = pIdPadOrigen) OR
		(Coalesce(CodValBto,'') = pCodValBto AND IdPadOrigen IS NULL AND pIdPadOrigen IS NULL)
		); 

	IF (vIdVal IS NOT NULL) THEN
		vTipocom := null;
		
		SELECT comm.TipoCom, comm.Letra, comm.NroPtoVta, comm.Nro, comm.Fecha 
		INTO vTipoCom, vLetra, vPtoVta, vNro, vFecha
		FROM ctem 
		INNER JOIN comm ON (ctem.idcomm   = comm.id)
		INNER JOIN valt ON (ctem.tipovalt = valt.tipo)
		WHERE ( 
			((SELECT SIGNO FROM CTEM WHERE AAOID = (SELECT max(aaoid) FROM ctem WHERE idval = vIdVal))= 1) 
			-- Si el último ENTRÓ.. AHÍ TENDREMOS PROBLEMAS, pero si el último salío no problem !!!!
			or CV = 'P') AND (ctem.aaoid = (SELECT max(aaoid) FROM ctem cte WHERE cte.idval = vIdVal));

		IF vTipoCom is not null THEN -- SI NO ES NULL ENTONCES ESTABA VOLVIENDO A ENTRAR LUEGO DE HABER SALIDO, LO DEJAMOS 
			vTexto := 'El valor ya fue ingresado en el sistema en la operacion: ' || chr(13) || ' Comprobante = ';
			vTexto := vTexto || COALESCE(vTipoCom,'') || ' ';
			IF (vLetra IS NOT NULL) THEN
				vTexto := vTexto || ' - Letra =  ' || vLetra || ' ';
			END IF;
			IF (vPtoVta IS NOT NULL) THEN 
				vTexto := vTexto || ' - Puesto = ' || vPtoVta;
			END IF;
			IF (vNro IS NOT NULL) THEN
				vTexto := vTexto || ' - Numero = ' || vNro;
			END IF;
			IF (vFecha IS NOT NULL) THEN
				vTexto := vTexto || '; Fecha = ' || vFecha;
			END IF;
				vTexto := translate(vTexto, 'áéíóúñÁÉÍÓÚÑäëïöüÄËÏÖÜºª¨ç¿¡´', 'aeiounAEIOUNaeiouAEIOU   _  `');
			RAISE EXCEPTION '%', vTexto;
		ELSE
			if vImpoMoneda <> pImpoMoneda then
				vTexto := 'Existe el mismo valor pero con otro importe, la operación es errónea, antes :' 
				|| vImpoMoneda || ' ahora: ' || pImpoMoneda; 
				RAISE EXCEPTION '%', vTexto;
			else 
				vTexto := 'Existe el mismo valor :' || vImpoMoneda || ' ahora: ' || pImpoMoneda; 
				RAISE EXCEPTION '%', vTexto;
			end if;
		END IF;
	END IF; 
END IF; -- Si no se cumple el if no se controla unicidad para el tipo de valor.

select count(*) 
	from valche 
	where idpad = pIdPadOrigen and TipoValt = pTipoValt and habilitada = 'S'                   
	into vcheqxbanco;

if (vChequera = 'S') and (pNro is not null) and (vcheqxbanco > 0) then
	if not (exists (select * from valche where idpad = pIdPadOrigen and 
		TipoValt = pTipoValt and habilitada = 'S' and                  
		to_number(pNro,'99999999') >= nroinic and 
		to_number(pNro,'99999999') <= NroFin ))
	THEN
		vTexto := 'El nro. de cheque ingresado no pertenece a ninguna chequera habilitada';
		RAISE EXCEPTION '%',vTexto;
	END IF;
END IF; 
RETURN TRUE;
END;
$BODY$;

ALTER FUNCTION public.verifica_unicidad_valor(character varying, character varying, character varying, integer, integer, numeric, character varying)
    OWNER TO abacouser;



--
SELECT aaVersion('517.02','517.01');
--	
	
	


